<template>
  <div class="page-controller" :class="{ swiping }" ref="pageController">
    <div
      v-for="(page, i) in pages"
      class="swipe-item"
      :class="{
        curr: currIndex === i,
        prev: prevIndex === i,
        next: nextIndex === i,
        'prev-out': prevIndex > i,
        'next-out': nextIndex < i,
        backing: isBackingToFirst,
      }"
      :key="page.id"
      :style="{
        transitionDuration: i >= prevIndex && i <= nextIndex ? transitionDuration : '',
        transform: swiping
          ? currIndex === i
            ? currTranslateX
            : prevIndex === i
            ? prevTranslateX
            : nextIndex === i
            ? nextTranslateX
            : ''
          : '',
      }"
      @transitionend.self="transitionEnd"
    >
      <Page
        :page="page"
        :index="i"
        :active="active && currIndex === i"
        :ready="active && i >= prevIndex && i <= nextIndex"
        @back="emits('back')"
      ></Page>
    </div>
  </div>
</template>

<script setup>
import { computed, inject, ref, watch } from 'vue'
import { usePreventTouchmove } from '@/compositions/mobile/preventTouchmove'
import { useSwipe } from '@/compositions/mobile/swipe'
import Page from './Page.vue'

const emits = defineEmits(['update:modelValue', 'back'])

const viewerRouter = inject('viewerRouter')
const { currIndex, pages, active, isBackingToFirst, noData, next, prev, setFPAR, transitFPAR, routeComplete } =
  viewerRouter

const HALF_VIEW_WIDTH = window.innerWidth / 2
const pageController = ref(null)
const prevIndex = computed(() => currIndex.value - 1)
const nextIndex = computed(() => currIndex.value + 1)

// 滑動操作
const { offset, swiping, transitionDuration, resetTransitionDuration } = useSwipe(pageController, {
  isBlockBackward: () => currIndex.value === 0,
  isBlockForward: () => currIndex.value === pages.value.length - 1 || noData.value,
  onBackward: prev,
  onForward: next,
  onRevert: transitFPAR,
})
watch(offset, (v) => {
  if (v < 0 && currIndex.value === 1) {
    setFPAR(Math.min(1, -v / (HALF_VIEW_WIDTH * 2)))
  }
  if (v > 0 && currIndex.value === 0) {
    setFPAR(Math.max(0, 1 - v / (HALF_VIEW_WIDTH * 2)))
  }
})

// 滑動中關閉瀏覽器預設行為
usePreventTouchmove(pageController, () => offset.value !== 0)

// 滑動時的樣式
const swipeLeft = computed(() => offset.value > 0)
const swipeRight = computed(() => offset.value < 0)
const currTranslateX = computed(() => {
  if (swiping.value) {
    if (swipeLeft.value) {
      const _offset = Math.min(offset.value, HALF_VIEW_WIDTH * 2)
      const dist = Math.floor(-_offset * 0.3)
      return `translateX(${dist}px)`
    }
    if (swipeRight.value) {
      const _offset = Math.min(-offset.value, HALF_VIEW_WIDTH * 2)
      return `translateX(${_offset}px)`
    }
  }
  return ''
})
const prevTranslateX = computed(() => {
  if (swiping.value) {
    if (swipeRight.value) {
      const _offset = Math.min(-offset.value, HALF_VIEW_WIDTH * 2)
      const dist = Math.floor(_offset * 0.3)
      return `translateX(calc(-30% + ${dist}px))`
    }
  }
  return ''
})
const nextTranslateX = computed(() => {
  if (swiping.value) {
    if (swipeLeft.value) {
      const _offset = Math.min(offset.value, HALF_VIEW_WIDTH * 2)
      return `translateX(calc(100% - ${_offset}px))`
    }
  }
  return ''
})

function transitionEnd(evt) {
  if (evt.target.classList.contains('curr')) {
    routeComplete()
    resetTransitionDuration()
  }
}
</script>

<style lang="scss" scoped>
.page-controller {
  width: 100%;
  height: 100%;
  position: relative;
  overflow: hidden;

  &.swiping {
    .swipe-item {
      transition: none;
      &.curr,
      &.prev,
      &.next {
        will-change: transform;
      }
    }
  }

  .swipe-item {
    width: 100%;
    height: 100%;
    position: absolute;
    transition: transform 0.25s ease-out;

    &.backing {
      transition: transform 0.08s ease-out;
    }

    &.prev,
    &.prev-out {
      transform: translateX(-30%);
    }

    &.next,
    &.next-out {
      transform: translateX(100%);
    }

    &.prev-out,
    &.next-out {
      display: none;
    }
  }
}
</style>
